// Copyright (C) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Reflection;
using System.ComponentModel;
using System.Drawing;

namespace Microsoft.VSPowerToys.VSCmdShell
{
    /// <summary>
    /// This class contains all static utility methods used throughout this project.
    /// </summary>
    static class Utils
    {
        /// <summary>
        /// Splits a command line in to its arguments taking quotes into account
        /// </summary>
        /// <param name="command">Command line to split</param>
        /// <returns>an array of strings containing the command itself and arguments</returns>
        public static string[] SplitCommand(string command, out int lastArgumentIndex)
        {
            List<string> arguments = new List<string>();
            StringBuilder currentArgument = new StringBuilder();
            bool inQuotes = false;
            char[] chars = command.ToCharArray();
            int lastBeginIndex = 0;
            for (int i =0;i < chars.Length; i++)
            {
                char c = chars[i];
                if (c == ' ' && !inQuotes && currentArgument.Length > 0)
                {
                    arguments.Add(currentArgument.ToString());
                    currentArgument = new StringBuilder();
                    lastBeginIndex = i + 1;
                    continue;
                }
                else if (c == '"')
                {
                    inQuotes = !inQuotes;
                    currentArgument.Append(c);
                    continue;
                }
                else
                {
                    currentArgument.Append(c);
                }
            }
            if (currentArgument.Length > 0 || lastBeginIndex == command.Length)
            {
                arguments.Add(currentArgument.ToString());
            }
            lastArgumentIndex = lastBeginIndex;
            return arguments.ToArray();
        }

        /// <summary>
        /// Returns the registry key for code window font and colors options.
        /// </summary>
        public static RegistryKey CodeWindowSettingsKey
        {
            get
            {
                return Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\VisualStudio\8.0\FontAndColors\" +
                    Strings.CodeWindowGUID);
            }
        }

        /// <summary>
        /// Returns a description for an enum value taken from Description attribute.
        /// If not present returns enum value as name.
        /// </summary>
        /// <param name="value">Enum value to get description</param>
        /// <returns>Description of enum</returns>
        public static string GetEnumDescription(Enum value)
        {
            FieldInfo info = value.GetType().GetField(value.ToString());
            DescriptionAttribute[] attributes =
              (DescriptionAttribute[])info.GetCustomAttributes
              (typeof(DescriptionAttribute), false);
            return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
        }

        /// <summary>
        /// Tries to locate the enum value with given type and description
        /// </summary>
        /// <param name="value">Type of enum value to locate</param>
        /// <param name="description">Description of the enum value</param>
        /// <returns>Enum value that corresponds to given type and description,
        /// null is returned if entry could not be located</returns>
        public static Enum GetEnumFromDescription(System.Type type, string description)
        {
            FieldInfo[] infos = type.GetFields();
            foreach (FieldInfo info in infos)
            {
                DescriptionAttribute[] attributes =
                  (DescriptionAttribute[])info.GetCustomAttributes
                  (typeof(DescriptionAttribute), false);
                if ((attributes.Length > 0 && attributes[0].Description.Equals(description)) ||
                    info.Name.Equals(description))
                {
                    return (System.Enum)info.GetValue(null);
                }
            }
            return null;
        }

        /// <summary>
        /// Tries to retrieve font for code window from registry, if not present
        /// returns default one.
        /// </summary>
        public static System.Drawing.Font CodeWindowFont
        {
            get
            {
                System.Drawing.Font font = new System.Drawing.Font("Courier New", 8);
                if (CodeWindowSettingsKey != null)
                {
                    font = new System.Drawing.Font(CodeWindowSettingsKey.GetValue("FontName", "Courier New").ToString(),
                        (int)(CodeWindowSettingsKey.GetValue("FontPointSize", 8)));
                }
                return font;
            }
        }

        /// <summary>
        /// Tries to retrieve foreground color for code window from registry, if not present
        /// returns the default one (Black)
        /// </summary>
        public static System.Drawing.Color CodeWindowForeColor
        {
            get
            {
                System.Drawing.Color foreColor = System.Drawing.Color.Black;
                if (CodeWindowSettingsKey != null)
                {
                    int color = (int)(CodeWindowSettingsKey.GetValue("Plain Text Foreground", 0xffffffff));
                    if (color != 0x02000000)
                    {
                        foreColor = VisualStudioValueToColor(color);
                    }
                }
                return foreColor;
            }
        }

        /// <summary>
        /// Tries to retrieve background color for code window from registry, if not present
        /// returns the default one (White)
        /// </summary>
        public static System.Drawing.Color CodeWindowBackColor
        {
            get
            {
                System.Drawing.Color backColor = System.Drawing.Color.White;
                if (CodeWindowSettingsKey != null)
                {
                    int color = (int)(CodeWindowSettingsKey.GetValue("Plain Text Background",0xff000000));
                    if (color != 0x02000000)
                    {
                        backColor = VisualStudioValueToColor(color);
                    }
                }
                return backColor;
            }
        }

        /// <summary>
        /// Convers color information stored in registry by Visual Studio to Color object
        /// </summary>
        /// <param name="vsColor">Integer value from registry</param>
        /// <returns></returns>
        private static Color VisualStudioValueToColor(int vsColor)
        {
            uint rawColor = (uint)vsColor;
            int red = (int)(rawColor & 0xff);
            int green = (int)((rawColor & 0xff00) >> 8);
            int blue = (int)((rawColor & 0xff0000) >> 16);
            return Color.FromArgb(red, green, blue);

        }
    }
}
